package com.stu.info;

import java.util.ListIterator;
import java.text.NumberFormat;
import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.Gravity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

import com.stu.aq.*;
import com.stu.graph.*;
import com.stu.usb.SerialIOManager;
import com.stu.widget.*;

public class GraphFragment extends CommandFragment implements CheckBox.OnCheckedChangeListener {
	public ArrayList<DataSeries> graphSeries;
	public float minX, maxX, minY, maxY;

	protected GraphView graphView;
	protected VerLabelsView verLabels;
	protected HorLabelsView horLabels;
	protected TextView label;
	protected TableLayout legend;
	protected CheckBox selectAll;

	private static NumberFormat xFormat, yFormat, vFormat;
	private float scrollThreshold, windowThreshold, scrollAmount;

	private class ColorChip extends View {
		private Paint paint;
		private Rect r;
		private final static int size = 15;
		
		public ColorChip( Context c, int color ) {
			super( c );
			paint = new Paint();
			paint.setColor( color );
			paint.setStrokeWidth( 0 );
			r = new Rect( 0, 0, size, size );
		}
	
		@Override
		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
			setMeasuredDimension( size, size );
		}

		@Override
		protected void onDraw(Canvas canvas) {
			canvas.drawRect( r, paint );
		}
		
	}
	
	public GraphFragment() {
		graphSeries = new ArrayList<DataSeries>();
		maxX = 0;
		minX = 0;
		maxY = 0;
		minY = 0;
		windowThreshold = GraphView.GraphViewConfig.SCROLL_THRESHOLD;
		scrollAmount = GraphView.GraphViewConfig.SCROLL_AMOUNT;
		xFormat = NumberFormat.getNumberInstance();
		xFormat.setMaximumFractionDigits( 0 );
		xFormat.setMinimumFractionDigits( 0 );
		yFormat = NumberFormat.getNumberInstance();
		yFormat.setMaximumFractionDigits( 1 );
		yFormat.setMinimumFractionDigits( 1 );
		vFormat = NumberFormat.getNumberInstance();
		vFormat.setMaximumFractionDigits( 1 );
		vFormat.setMinimumFractionDigits( 1 );
	}

	/**
	 * Initialize the graph with default grids and scrolls.
	 * @param v Parent view of the graph and labels
	 * @param title
	 */
	public void init( View v, String title ) {
		init( v, title, GraphView.GraphViewConfig.GRID_X, GraphView.GraphViewConfig.GRID_Y,
		  GraphView.GraphViewConfig.SCROLL_THRESHOLD, GraphView.GraphViewConfig.SCROLL_AMOUNT );
	}
	
	/**
	 * Initialize the graph and labels
	 * @param v Parent view of the graph and labels
	 * @param title
	 * @param gridX
	 * @param gridY
	 * @param scrollThreshold
	 * @param scrollAmount
	 */
	public void init( View v, String title, int gridX, int gridY, float scrollThreshold, float scrollAmount ) {
		this.scrollThreshold = scrollThreshold;
		this.scrollAmount = scrollAmount;
		windowThreshold = scrollThreshold;
		graphView = (GraphView)v.findViewById( R.id.graphView );
		graphView.gridX = gridX;
		graphView.gridY = gridY;
		graphView.setFragment( this );
		horLabels = (HorLabelsView)v.findViewById( R.id.horLabelsView );
		horLabels.setFragment( this );
		verLabels = (VerLabelsView)v.findViewById( R.id.verLabelsView );
		verLabels.setFragment( this );
		label = (TextView)v.findViewById( R.id.label );
		label.setText( title );
		legend = (TableLayout)v.findViewById( R.id.legend );
		selectAll = (CheckBox)v.findViewById( R.id.selectAll );
		selectAll.setOnCheckedChangeListener( this );
		getLimits();
		addLegend( v );
	}

	private void addLegend( View v ) {
		int position = 0;
		
		for( DataSeries ds : graphSeries ) {
			TableRow r = new TableRow( v.getContext() );
			
			CheckBox cb = new CheckBox( v.getContext() );
			cb.setId( position );		// used by listener
			cb.setChecked( true );
			cb.setOnCheckedChangeListener( this );
			r.addView( cb );
			
			ColorChip cc = new ColorChip( v.getContext(), ds.style.color );
			TableRow.LayoutParams p = new TableRow.LayoutParams();
			p.gravity = Gravity.CENTER;
			cc.setLayoutParams( p );	// tell the row to put me in the center
			r.addView( cc );
			
			TextView t = new TextView( v.getContext() );
			t.setText( ds.name );
			t.setTextSize( 12f );
			t.setPadding( 5, 0, 0, 0 );
			r.addView( t );

			t = new TextView( v.getContext() );
			t.setId( 256+position );
			t.setTextSize( 12f );
			t.setGravity( Gravity.RIGHT );
			r.addView(  t );

			legend.addView( r );
			position++;
		}
	}

	public void reset() {
		graphSeries = new ArrayList<DataSeries>();
		legend.removeAllViews();
		maxX = 0;
		minX = 0;
		maxY = 0;
		minY = 0;
		windowThreshold = scrollThreshold;
		label.invalidate();
		verLabels.reset();
		horLabels.reset();
		graphView.invalidate();
		verLabels.invalidate();
		horLabels.invalidate();
	}

	public void updateViews() {
		getLimits();
		int ix = 0;
		for( DataSeries d : graphSeries ) {
			if( d.visible && !d.values.isEmpty() )
				((TextView)legend.findViewById(256+ix)).setText( vFormat.format(d.values.getLast().y) );
			ix++;
		}
		label.invalidate();
		graphView.invalidate();
		verLabels.invalidate();
		horLabels.invalidate();
	}

	private void getLimits() {
		// pass 1: get maxX and minX for all data sets
		float max = 0;
		for( DataSeries d : graphSeries ) {
			if( !d.values.isEmpty() ) {
				// x values are sorted by size
				if( d.values.getLast().x > max )
					max = d.values.getLast().x;
			}
		}
		if( max == 0 )
			maxX = graphView.gridX;
		else if( max > windowThreshold ) {
			// scroll window
			minX += scrollAmount;
			maxX = minX + graphView.gridX;
			windowThreshold += scrollAmount;
		}
		// pass 2: remove all points less than minX and
		//  get minY and maxY of remaining points
		for( DataSeries d : graphSeries ) {
			if( !d.values.isEmpty() ) {
				ListIterator<PointF> itr = d.values.listIterator();
				while( itr.hasNext() ) {
					if( itr.next().x < minX )
						itr.remove();
				}
				for( PointF p : d.values ) {
					if( p.y > maxY )
						maxY = p.y;
					if( p.y < minY )
						minY = p.y;
				}
			}
		}
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		int ix = 0;
		switch( buttonView.getId() ) {
			case R.id.selectAll:
				for( DataSeries d : graphSeries ) {
					d.visible = isChecked;
					((CheckBox)legend.findViewById(ix)).setChecked( isChecked );
					ix++;
				}
				break;
			default:
				graphSeries.get( buttonView.getId() ).visible = isChecked;
		}
		graphView.invalidate();
	}

	public static String formatLabel(float value, boolean isValueX) {
		if( isValueX )
			return xFormat.format(value);
		return yFormat.format(value);
	}

	@Override
	public void update(OnCommandListener l, SerialIOManager io) {
	}

	@Override
	public void updateUI(Object statusData) {
	}

	@Override
	public void clear() {
		int rows = legend.getChildCount();
		for( int i = 0; i < rows; i++ )
			((TextView)legend.findViewById(256+i)).setText( "" );
		graphSeries = new ArrayList<DataSeries>();
		maxX = 0;
		minX = 0;
		maxY = 0;
		minY = 0;
		windowThreshold = scrollThreshold;
		verLabels.reset();
		horLabels.reset();
		graphView.invalidate();
		verLabels.invalidate();
		horLabels.invalidate();
	}

	@Override
	public void stopUpdate(OnCommandListener l, SerialIOManager io) {
	}

	@Override
	public void write(OnCommandListener l, SerialIOManager io) {
	}

}
